#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include "aimage.h"

APIXEL::APIXEL( float ar, float ag, float ab )
{
	r = (int) ((( float ) FULL_INT) * ar );
	g = (int) ((( float ) FULL_INT) * ag );
	b = (int) ((( float ) FULL_INT) * ab );
}

APIXEL::APIXEL( double ar, double ag, double ab )
{
	r = (int) ((( double ) FULL_INT) * ar );
	g = (int) ((( double ) FULL_INT) * ag );
	b = (int) ((( double ) FULL_INT) * ab );
}

APIXEL::APIXEL( PIXVAL ra, PIXVAL ga, PIXVAL ba )
{
	r = ra;
	g = ga;
	b = ba;
}

AVECTOR::AVECTOR( const APIXEL &src )
{
	x = ( float ( src.r )) / ((float ) FULL_INT );
	y = ( float ( src.g )) / ((float ) FULL_INT );
	z = ( float ( src.b )) / ((float ) FULL_INT );
	w = 1.0f;
}

AVECTOR::AVECTOR( void )
{
}

AVECTOR::AVECTOR( int a )
{
	x = 0.0f;
	y = 0.0f;
	z = 0.0f;
	w = 1.0f;
}

AVECTOR AVECTOR::operator +( const AVECTOR &a)
{
	AVECTOR r;
	r.x = x + a.x;
	r.y = y + a.y;
	r.z = z + a.z;
	return r;
}

AVECTOR AVECTOR::operator -( const AVECTOR &a)
{
	AVECTOR r;
	r.x = x - a.x;
	r.y = y - a.y;
	r.z = z - a.z;
	return r;
}

AVECTOR AVECTOR::operator *( float f )
{
	AVECTOR r;
	r.x = f * x;
	r.y = f * y;
	r.z = f * z;
	return r;
}

float AVECTOR::mag( void )
{
	return sqrt( x*x + y*y + z*z );
}

void AVECTOR::normalize( void )
{
	float scale = 1.0f / mag();
	x *= scale;
	y *= scale;
	z *= scale;
}

AIMAGE::AIMAGE()
{
	m_height=-1;
	m_width=-1;
	m_image=NULL;
}

void AIMAGE::alloc_image( int width, int height )
{
	int y;

	if ( m_width == width && m_height == height )
	{
		return;
	}
	free_image();

	m_width = width;
	m_height = height;

	assert( m_width>0 && m_width < 10*1024 );
	assert( m_height>0 && m_height < 10*1024 );

	m_image = new APIXEL *[ m_height ];
	m_image[0] = new APIXEL [ m_height * m_width ];

	for ( y = 1; y< m_height; ++y )
		m_image[ y ] = m_image[ 0 ]+ m_width * y;
}

void AIMAGE::free_image( void )
{
	if ( m_image != NULL )
	{
		delete[] m_image[0];
		delete[] m_image;
		m_image = NULL;
		m_width = -1;
		m_height = -1;
	}
	assert( m_width == -1 );
	assert( m_height == -1 );
}

AIMAGE::~AIMAGE( void )
{
	free_image();
}

void AIMAGE::hueshift( float gamma )
{
	APIXEL *begin, *end, *cur;
	begin = m_image[ 0 ];
	end = begin + ( m_width * m_height );

	for ( cur = begin; cur != end; ++cur )
	{
		int r;
		r = cur->r;
		cur->r = cur->b;
		cur->b = r;
#ifdef gone
		AHSV hsv = pixel_to_hsv( *cur );
		//hsv.h = 360 -90 - hsv.h;
		hsv.h /= 360.0f;
		hsv.h = expf( logf( hsv.h ) * gamma );
		hsv.h *= 360.0f;
		//fprintf(stderr, "R=%d G=%d B=%d   H=%f S=%f V=%f\n",
		//	cur->r, cur->g, cur->b,
		//	hsv.h, hsv.s, hsv.v );
		*cur = hsv_to_pixel( hsv );
#endif
	}
}

AIMAGE::iterator AIMAGE::begin( void )
{
	AIMAGE::iterator b;
	b.p = m_image[ 0 ];
	return b; 
}

AIMAGE::iterator AIMAGE::end( void )
{
	AIMAGE::iterator e;
	e.p = m_image[ 0 ] + ( m_width * m_height );
	return e; 
}

AIMAGE::const_iterator AIMAGE::const_begin( void ) const
{
	AIMAGE::const_iterator b;
	b.p = m_image[ 0 ];
	return b; 
}

AIMAGE::const_iterator AIMAGE::const_end( void ) const
{
	AIMAGE::const_iterator e;
	e.p = m_image[ 0 ] + ( m_width * m_height );
	return e; 
}

void AIMAGE::scale_by_256( void )
{
	APIXEL p;
	APIXEL *begin, *end, *cur;

	begin = m_image[ 0 ];
	end = begin + ( m_width * m_height );

	for ( cur = begin; cur != end; ++cur )
	{
		cur->r >>=8;
		cur->g >>=8;
		cur->b >>=8;
	}
}

void AIMAGE::makemask( float arg_cutoff )
{
	APIXEL *begin, *end, *cur;

	begin = m_image[ 0 ];
	end = begin + ( m_width * m_height );

	int cutoff = FULL_INT * arg_cutoff * 10;

	for ( cur = begin; cur != end; ++cur )
	{
		int intensity;

		intensity = cur->r * 3 + cur->g * 6 + cur->b;

		if ( intensity > cutoff )
		{
			cur->r = FULL_INT;
			cur->g = FULL_INT;
			cur->b = FULL_INT;
		}
		else
		{
			cur->r = 0;
			cur->g = 0;
			cur->b = 0;
		}
	}
}

void AIMAGE::copy( const AIMAGE &src, int xs, int ys,
	int xw, int yw, int xd, int yd )
{
	assert( xs >= 0 );
	assert( ys >= 0 );
	assert( xw >= 0 );
	assert( xd >= 0 );
	assert( yd >= 0 );

	assert( xs + xw <= src.m_width );
	assert( ys + yw <= src.m_height );
	assert( xd + xw <= m_width );
	assert( yd + yw <= m_height );

	int iys, iys_end;
	int iyd;
	int copy_mem = xw * sizeof( APIXEL );

	for ( 	iys = ys, iys_end = ys + yw, iyd = yd;
		iys < iys_end;
		iys++, iyd++ )
	{
		const APIXEL *srcp = src.m_image[ iys ] + xs;
		APIXEL *dstp = m_image[ iyd ] + xd;
		memcpy( dstp, srcp, copy_mem);
	}
}
